package com.engine.jucailinkq.common.util;

import org.apache.commons.lang3.StringUtils;
import weaver.general.TimeUtil;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DateUtil {
    public static DateTimeFormatter yyyyMMdd = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    public static DateTimeFormatter yyyyMMddHHmmss = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    public static DateTimeFormatter yyyyMMddHHmm = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    public static DateTimeFormatter yyyyMM = DateTimeFormatter.ofPattern("yyyy-MM");
    public static DateTimeFormatter yyyy = DateTimeFormatter.ofPattern("yyyy");

    /**
     * yyyy-MM
     **/
    private static final String MONTH_REGEX = "^([1-9]\\d{3})-(([0][1-9])|([1][0-2]))$";
    /**
     * yyyy-MM-dd,仅格式匹配，实际值的合理性不做要求
     **/
    private static final String DATE_PATTERN = "^\\d{4}-\\d{2}-\\d{2}$";

    public static String beforeMonth(String time,int month){
        LocalDateTime localDateTime = DateUtil.getTime(time);
        return localDateTime.minusMonths(month).format(yyyyMMdd);
    }

    public static String beforeMonth(String time){
        LocalDateTime localDateTime = DateUtil.getTime(time);
        return localDateTime.minusMonths(1).format(yyyyMM);
    }

    public static String lastMonth(String time){
        LocalDateTime localDateTime = DateUtil.getTime(time);

        return localDateTime.plusMonths(1).format(yyyyMM);
    }
    public static String lastMonth(String time,DateTimeFormatter dateTimeFormatter){
        LocalDateTime localDateTime = DateUtil.getTime(time);

        return localDateTime.plusMonths(1).format(dateTimeFormatter);
    }
    public static String nextMonth(String time,int month,DateTimeFormatter dateTimeFormatter){
        LocalDateTime localDateTime = DateUtil.getTime(time);

        return localDateTime.plusMonths(month).format(dateTimeFormatter);
    }
    public static String nextYear(String time,int year,DateTimeFormatter dateTimeFormatter){
        LocalDateTime localDateTime = DateUtil.getTime(time);

        return localDateTime.plusYears(year).format(dateTimeFormatter);
    }
    public static String beforeYear(String time,int year,DateTimeFormatter dateTimeFormatter){
        LocalDateTime localDateTime = DateUtil.getTime(time);

        return localDateTime.minusYears(year).format(dateTimeFormatter);
    }


    public static String beforeDay(String time,long day){
        LocalDateTime localDateTime = LocalDate.parse(time, yyyyMMdd).atStartOfDay();
        return localDateTime.minusDays(day).format(yyyyMMdd);
    }
    public static String AfterDay(String time,long day){
        LocalDateTime localDateTime = LocalDate.parse(time, yyyyMMdd).atStartOfDay();

        return localDateTime.plusDays(day).format(yyyyMMdd);
    }

    public static String beforeMinutes(String time,long minutes){
        LocalDateTime localDateTime = DateUtil.getTime(time);
        return localDateTime.minusMinutes(minutes).format(yyyyMMddHHmm);
    }

    public static String AfterMinutes(String time,long minutes){
        LocalDateTime localDateTime = DateUtil.getTime(time);
        return localDateTime.plusMinutes(minutes).format(yyyyMMddHHmm);
    }
    public static String AfterSeconds(String time,long seconds){
        LocalDateTime localDateTime = DateUtil.getTime(time);
        return localDateTime.plusSeconds(seconds).format(yyyyMMddHHmmss);
    }

    public static String nowMonth(String time){
        LocalDateTime localDateTime = LocalDate.parse(time, yyyyMMdd).atStartOfDay();
        return localDateTime.format(yyyyMM);
    }

    public static String getCurrentMonth(){
        return LocalDateTime.now().format(yyyyMM);
    }
    public static String getCurrentDate(){
        return LocalDateTime.now().format(yyyyMMdd);
    }
    public static String getCurrentTime(){
        return LocalDateTime.now().format(yyyyMMddHHmmss);
    }
    public static String getCurrentTime(String timeType){
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(timeType);
        return LocalDateTime.now().format(formatter);
    }

    //获得往后日期
    public static String getCurrentDatePlusDay(int day){
        return LocalDateTime.now().plusDays(day).format(yyyyMMdd);
    }
    //获得往前日期
    public static String getCurrentDateMinusDay(int day){
        return LocalDateTime.now().minusDays(day).format(yyyyMMdd);
    }


    public static LocalDateTime getTime(String time){
        int length = time.length();
        switch (length){
            case 10:
                return LocalDate.parse(time, yyyyMMdd).atStartOfDay();
            case 19:
                return LocalDateTime.parse(time, yyyyMMddHHmmss);
            case 16:
                return LocalDateTime.parse(time, yyyyMMddHHmm);
        }
        return null;
    }


    /**
     * 获得时间与当前相差的小时
     * @param startTime 开始时间 yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static long getBetWeenHours(String startTime){

        Duration duration = Duration.between(LocalDateTime.parse(startTime,yyyyMMddHHmmss),LocalDateTime.now());

        return duration.toHours();
    }
    /**
     * 获得两个时间相差的年份
     * @param startTime 开始时间 yyyy-MM-dd
     * @return
     */
    public static int getBetWeenYears(String startTime){
        Period duration = Period.between(LocalDate.parse(startTime,yyyyMMdd),LocalDateTime.now().toLocalDate());

        return duration.getYears();
    }

    /**
     * 获得两个时间相差的年份
     * @param startTime 开始时间 yyyy-MM-dd
     * @return
     */
    public static int getBetWeenYears(String startTime,String endTime){
        Period duration = Period.between(LocalDate.parse(startTime,yyyyMMdd),LocalDate.parse(endTime,yyyyMMdd));
        return duration.getYears();
    }

    /**
     * 获得两个时间相差的月份
     * @param startTime 开始时间 yyyy-MM-dd
     * @return
     */
    public static int getBetWeenMonths(String startTime,String endTime){
        LocalDateTime startDate = DateUtil.getTime(startTime);
        LocalDateTime endDate = DateUtil.getTime(endTime);

        YearMonth startYearMonth = YearMonth.from(startDate);
        YearMonth endYearMonth = YearMonth.from(endDate);

        int betweenMonth = (int) ChronoUnit.MONTHS.between(startYearMonth, endYearMonth);
//        if (startDate.getDayOfMonth()>endDate.getDayOfMonth()){
//            betweenMonth= betweenMonth-1;
//        }
        return betweenMonth;
    }

    /**
     * 获得当前时间相差的天数
     * @param startTime 开始时间 yyyy-MM-dd
     * @return
     */
    public static int getBetWeenDays(String startTime){
        LocalDate startDate = LocalDate.parse(startTime);
        LocalDate endDate = LocalDateTime.now().toLocalDate();

        long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);
        return Math.toIntExact(daysBetween);
    }
    /**
     * 获得当前时间相差的天数
     * @param startTime 开始时间 yyyy-MM-dd
     * @return
     */
    public static int getBetWeenDays(String startTime,String endTime){
        LocalDate startDate = LocalDate.parse(startTime);
        LocalDate endDate = LocalDate.parse(endTime);

        long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);
        return Math.toIntExact(daysBetween);
    }
    /**
     * 获得当前时间相差的分钟数
     * @param startTime 开始时间 yyyy-MM-dd
     * @return
     */
    public static int getBetWeenMinutes(String startTime,String endTime,DateTimeFormatter formatter){
        LocalDateTime startDate = LocalDateTime.parse(startTime,formatter);
        LocalDateTime endDate = LocalDateTime.parse(endTime,formatter);

        long daysBetween = ChronoUnit.MINUTES.between(startDate, endDate);
        return Math.toIntExact(daysBetween);
    }
    /**
     * 获得当前时间相差的分钟数
     * @param startTime 开始时间 yyyy-MM-dd
     * @return
     */
    public static int getBetWeenMinutes(String startTime,String endTime){
        LocalDateTime startDate = DateUtil.getTime(startTime);
        LocalDateTime endDate = DateUtil.getTime(endTime);

        long daysBetween = ChronoUnit.MINUTES.between(startDate, endDate);
        return Math.toIntExact(daysBetween);
    }

    /**
     * 获得两个时间相差的小时
     * @param startTime 开始时间 yyyy-MM-dd HH:mm:ss
     * @param endTime 结束时间 yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static long getBetWeenHours(String startTime,String endTime){
        Duration duration = Duration.between(getTime(startTime),getTime(endTime));

        return duration.toHours();
    }

    /**
     * 获得两个时间相差的周
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return
     */
    public static int getBetweenWeeks(String startTime,String endTime){
        int days = getBetWeenDays(startTime,endTime);
        int dayOfWeek = TimeUtil.getDayOfWeek(startTime);
        if (dayOfWeek == 0){
            dayOfWeek = 7;
        }
        days = days-(7-dayOfWeek);

        return days/7;
    }


    /**
     * 获得该月份的天数
     * @param time
     * @return
     */
    public static int getDays(String time,int CalendarType){
        Calendar calendar = Calendar.getInstance();
        calendar.set(Integer.valueOf(time.split("-")[0]), Integer.valueOf(time.split("-")[1]) - 1, 1);
        return calendar.getActualMaximum(CalendarType);
    }

    public static String getTimeStr(int value){
        String str = "";
        if (value < 10){
            str = "0"+value;
        }else {
            str = String.valueOf(value);
        }
        return str;
    }

    /**
     * 获得所处季度的
     */
    public static String getCurrentQuarter(String date){
        String season1 = date.split("-")[0]+"-03-31";
        String season2 = date.split("-")[0]+"-06-30";
        String season3 = date.split("-")[0]+"-09-30";
        String season4 = date.split("-")[0]+"-12-31";

        if (DateUtil.getTime(date).compareTo(DateUtil.getTime(season1)) <=0){
            return season1;
        }else if (DateUtil.getTime(date).compareTo(DateUtil.getTime(season1)) >0 &&
                DateUtil.getTime(date).compareTo(DateUtil.getTime(season2)) <=0){
            return season2;
        }else if (DateUtil.getTime(date).compareTo(DateUtil.getTime(season2)) >0 &&
                DateUtil.getTime(date).compareTo(DateUtil.getTime(season3)) <=0){
            return season3;
        }else{
            return season4;
        }
    }
    /**
     * 获得所处当前半年
     */
    public static String getCurrentHalfYear(String date){
        String season1 = date.split("-")[0]+"-06-30";

        if (DateUtil.getTime(date).compareTo(DateUtil.getTime(season1)) <=0){
            return season1;
        }else {
            return date.split("-")[0]+"-12-31";
        }
    }

    public static String getFormatLocalDate(Date date) {
        if (date == null) {
            return StringUtils.EMPTY;
        }
        LocalDateTime localDateTime = dateToLocalDateTime(date);
        return getFormatLocalDate(localDateTime);
    }
    public static String getFormatLocalDate(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            return StringUtils.EMPTY;
        }
        try {
            return localDateTime.format(yyyyMMdd);
        } catch (Exception e) {
            return StringUtils.EMPTY;
        }
    }
    public static LocalDateTime dateToLocalDateTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zone);
    }

    // 正则表达式用于匹配日期格式yyyy-MM-dd，不验证日期是否合法
    public static boolean dateIsValid(String date) {
        if (date == null) {
            return false;
        }
        // 编译正则表达式
        Pattern pattern = Pattern.compile(DATE_PATTERN);
        // 匹配日期字符串
        Matcher matcher = pattern.matcher(date);
        // 返回是否匹配的结果
        return matcher.matches();
    }

    /**
     * 检查年月格式
     *
     * @param yearMonth
     * @return
     */
    public static boolean checkYearMonth(String yearMonth) {
        return Pattern.matches(MONTH_REGEX, yearMonth);
    }

    /**
     * 获取两个日期间的日期集合
     * @param startDateStr
     * @param endDateStr
     * @return
     * @throws ParseException
     */
    public static List<String> getDatesBetween(String startDateStr, String endDateStr) throws ParseException {
        List<String> dates = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date startDate = sdf.parse(startDateStr);
        Date endDate = sdf.parse(endDateStr);

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);

        while (calendar.getTime().before(endDate) || calendar.getTime().equals(endDate)) {
            dates.add(sdf.format(calendar.getTime()));
            calendar.add(Calendar.DATE, 1);
        }
        return dates;
    }

    /**
     * 判断两个时间段是否有重叠部分
     */
    public static boolean isOverlapping(String startTime1, String endTime1, String startTime2, String endTime2) {
        // 如果结束时间小于另一个的开始时间，则不重叠
        if (endTime1.compareTo(startTime2) <= 0) {
            return false;
        }
        // 如果开始时间大于另一个的结束时间，则不重叠
        if (startTime1.compareTo(endTime2) >= 0) {
            return false;
        }
        // 否则，两个时间段重叠
        return true;
    }

    /**
     * 获取两个时间段重叠分钟数
     */
    public static int getOverlappedMinutes(String startTime1, String endTime1, String startTime2, String endTime2) {
        if (isOverlapping(startTime1, endTime1, startTime2, endTime2)) {
            // 取两个段的最大开始和最小结束时间
            String start = startTime1.compareTo(startTime2) >= 0 ? startTime1 : startTime2;
            String end = endTime1.compareTo(endTime2) <= 0 ? endTime1 : endTime2;
            // 计算重叠的分钟数
            return getBetWeenMinutes(start, end);
        }
        // 如果不重叠，返回0
        return 0;
    }

    /**
     * 获取日期在一年中属于第几周
     */
    public static int weekRank(String dateStr) throws Exception {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        Date date = formatter.parse(dateStr);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.setFirstDayOfWeek(Calendar.MONDAY);//设置星期一为一周开始的第一天
        return calendar.get(Calendar.WEEK_OF_YEAR);
    }
}
